"""
懒加载Docker服务
只在需要时创建Docker连接，自动管理连接生命周期
"""

import time
import threading
import logging
from typing import Optional, Dict, Any
import docker
from docker.client import DockerClient
from docker.errors import DockerException

logger = logging.getLogger('lazy_docker_service')

class LazyDockerService:
    def __init__(self):
        self._client: Optional[DockerClient] = None
        self._last_access_time = 0
        self._connection_timeout = 600  # 10分钟无访问自动释放连接
        self._lock = threading.Lock()
        self._cleanup_timer: Optional[threading.Timer] = None
    
    def get_client(self) -> Optional[DockerClient]:
        """获取Docker客户端，按需创建连接"""
        with self._lock:
            current_time = time.time()
            
            # 检查是否需要释放过期连接
            if (self._client and 
                (current_time - self._last_access_time) > self._connection_timeout):
                logger.debug("Docker连接超时，释放连接")
                self._close_client()
            
            # 如果没有连接，创建新连接
            if not self._client:
                try:
                    logger.debug("创建新的Docker客户端连接")
                    self._client = docker.from_env()
                    # 测试连接是否可用
                    self._client.ping()
                    logger.info("Docker客户端连接成功")
                except DockerException as e:
                    logger.error(f"无法连接到Docker: {str(e)}")
                    self._client = None
                    return None
                except Exception as e:
                    logger.error(f"Docker连接异常: {str(e)}")
                    self._client = None
                    return None
            
            # 更新最后访问时间
            self._last_access_time = current_time
            
            # 重置清理定时器
            self._reset_cleanup_timer()
            
            return self._client
    
    def _close_client(self):
        """关闭Docker客户端连接"""
        if self._client:
            try:
                self._client.close()
                logger.debug("Docker客户端连接已关闭")
            except Exception as e:
                logger.warning(f"关闭Docker连接时发生异常: {str(e)}")
            finally:
                self._client = None
    
    def _reset_cleanup_timer(self):
        """重置清理定时器"""
        if self._cleanup_timer:
            self._cleanup_timer.cancel()
        
        self._cleanup_timer = threading.Timer(
            self._connection_timeout, 
            self._auto_cleanup
        )
        self._cleanup_timer.daemon = True
        self._cleanup_timer.start()
    
    def _auto_cleanup(self):
        """自动清理超时连接"""
        with self._lock:
            current_time = time.time()
            if (self._client and 
                (current_time - self._last_access_time) > self._connection_timeout):
                logger.info("自动清理超时的Docker连接")
                self._close_client()
    
    def close_all_connections(self):
        """手动关闭所有连接"""
        with self._lock:
            if self._cleanup_timer:
                self._cleanup_timer.cancel()
                self._cleanup_timer = None
            self._close_client()
            logger.info("所有Docker连接已关闭")
    
    # Docker API包装方法
    def list_containers(self, all=False, filters=None):
        """列出容器"""
        client = self.get_client()
        if not client:
            return []
        
        try:
            return client.containers.list(all=all, filters=filters)
        except Exception as e:
            logger.error(f"列出容器失败: {str(e)}")
            return []
    
    def list_images(self, all=False, filters=None):
        """列出镜像"""
        client = self.get_client()
        if not client:
            return []
        
        try:
            return client.images.list(all=all, filters=filters)
        except Exception as e:
            logger.error(f"列出镜像失败: {str(e)}")
            return []
    
    def pull_image(self, image_name: str, tag: str = 'latest'):
        """拉取镜像"""
        client = self.get_client()
        if not client:
            return None
        
        try:
            logger.info(f"开始拉取镜像: {image_name}:{tag}")
            image = client.images.pull(image_name, tag=tag)
            logger.info(f"镜像拉取完成: {image_name}:{tag}")
            return image
        except Exception as e:
            logger.error(f"拉取镜像失败 {image_name}:{tag}: {str(e)}")
            return None
    
    def remove_image(self, image_id: str, force: bool = False):
        """删除镜像"""
        client = self.get_client()
        if not client:
            return False
        
        try:
            client.images.remove(image_id, force=force)
            logger.info(f"镜像删除成功: {image_id}")
            return True
        except Exception as e:
            logger.error(f"删除镜像失败 {image_id}: {str(e)}")
            return False
    
    def get_container(self, container_id: str):
        """获取容器对象"""
        client = self.get_client()
        if not client:
            return None
        
        try:
            return client.containers.get(container_id)
        except Exception as e:
            logger.error(f"获取容器失败 {container_id}: {str(e)}")
            return None
    
    def start_container(self, container_id: str):
        """启动容器"""
        container = self.get_container(container_id)
        if not container:
            return False
        
        try:
            container.start()
            logger.info(f"容器启动成功: {container_id}")
            return True
        except Exception as e:
            logger.error(f"启动容器失败 {container_id}: {str(e)}")
            return False
    
    def stop_container(self, container_id: str, timeout: int = 10):
        """停止容器"""
        container = self.get_container(container_id)
        if not container:
            return False
        
        try:
            container.stop(timeout=timeout)
            logger.info(f"容器停止成功: {container_id}")
            return True
        except Exception as e:
            logger.error(f"停止容器失败 {container_id}: {str(e)}")
            return False
    
    def restart_container(self, container_id: str, timeout: int = 10):
        """重启容器"""
        container = self.get_container(container_id)
        if not container:
            return False
        
        try:
            container.restart(timeout=timeout)
            logger.info(f"容器重启成功: {container_id}")
            return True
        except Exception as e:
            logger.error(f"重启容器失败 {container_id}: {str(e)}")
            return False
    
    def get_system_info(self):
        """获取Docker系统信息"""
        client = self.get_client()
        if not client:
            return {}
        
        try:
            return client.info()
        except Exception as e:
            logger.error(f"获取Docker系统信息失败: {str(e)}")
            return {}
    
    def get_version(self):
        """获取Docker版本信息"""
        client = self.get_client()
        if not client:
            return {}
        
        try:
            return client.version()
        except Exception as e:
            logger.error(f"获取Docker版本信息失败: {str(e)}")
            return {}
    
    def is_connected(self):
        """检查是否连接到Docker"""
        client = self.get_client()
        if not client:
            return False
        
        try:
            client.ping()
            return True
        except Exception:
            return False

# 全局单例
lazy_docker_service = LazyDockerService()

def get_lazy_docker_service() -> LazyDockerService:
    """获取懒加载Docker服务单例"""
    return lazy_docker_service